/*action :-  preconditions or actions,
           retract(affected_old_properties),
           assert(new_properties).*/


:- dynamic on/2.
:- dynamic handempty/0.
:- dynamic holding/1.
:- dynamic clear/1.
:- dynamic ontable/1.

putdown(A) :-
	A \== table,
	holding(A),
	retract(holding(A)),
	assert(clear(A)),
	assert(ontable(A)),
	assert(handempty).

pickup(A) :-
	A \== table,
	ontable(A),
	handempty,
	clear(A),
	retract(handempty),
	retract(clear(A)),
	retract(ontable(A)),
	assert(holding(A)).

stack(A,B) :-
	A \== table,
	A \== B,
	clear(A),
	clear(B),  /*Nothing is ontop of B*/
	holding(A),
	retract(holding(A)),
	assert(on(A,B)),
	assert(handempty),
	assert(clear(A)).

unstack(A,B) :-
	A \== table,
	A \== B,
	on(A,B),
	clear(A), /*Now nothing will be ontop of A*/
        handempty,
	retract(on(A,B)),
        retract(handempty),
	assert(holding(A)),
	assert(clear(B)).

clear(B) :-
     not(on(_X,B)).

/* ---------------Recursive Method-------------------*/

hold(A) :-
	holding(A).
/*holding done by pickup*/ 
hold(A) :-
	clear_off(A),
	ontable(A),
	pickup(A),
	assert(move(pickup(A))).

/*holding done by unstack*/ 
hold(A) :-
	clear_off(A),
	on(A,X),
	unstack(A,X),
	assert(move(unstack(A,X))).


/*put a on b is already there*/
r_put_on(A,B) :-
     on(A,B).

/*put a on b by pickup since a is on the table*/
r_put_on(A,B) :-	/*It's on the table*/
	not(on(A,B)),  /*A is not on B*/
	A \== table,
	A \== B,
	clear_off(A), /*Clear everything ontop of A*/
	clear_off(B), /*Clear everything ontop of B*/
	ontable(A),
	pickup(A),
	stack(A,B),
	assert(move(pickup(A))),
	assert(move(stack(A,B))).

/*put a on b by unstack since a on another block*/
r_put_on(A,B) :-	/*It's on another block*/
	not(on(A,B)),  /*A is not on B*/
	A \== table,
	A \== B,
	clear_off(A), /*Clear everything ontop of A*/
	clear_off(B), /*Clear everything ontop of B*/
	on(A,X),
	unstack(A,X),
	stack(A,B),
	assert(move(unstack(A,X))),
	assert(move(stack(A,B))).


/*clear what above*/
clear_off(table).    

clear_off(A) :-      /* Means already clear */
     not(on(_X,A)).

/*clear every one above*/
clear_off(A) :-
     A \== table,
     on(X,A),
     clear_off(X),      /* Recurse */
     retract(on(X,A)),
     assert(ontable(X)),
     assert(move(unstack(X,A))),
     assert(move(putdown(X))).
/*----------------------------------------------------*/

//goal
do(Glist) :-
      valid(Glist),
      do_all(Glist,Glist).

valid(_).                          /* Validation Function - Goal is True. *//* -will not implement- */

do_all([G|R],Allgoals) :-          /* Already True */
     call(G),
     do_all(R,Allgoals),!.         /* Continue with rest of goals */

do_all([G|_],Allgoals) :-
     achieve(G),
     do_all(Allgoals,Allgoals).    /* Check Again, that all goals completed */

do_all([],_Allgoals).              /* All Goals completed */

/*-------------------------------achieve each goal in the list---------------------------------------------*/
/*on goal
achieve(on(A,B)) :-
	r_put_on(A,B).

/*ontable goal
achieve(ontable(A)) :-
	ontable(A).

/*ontable goal
achieve(ontable(A)) :-
	clear_off(A),
	unstack(A,X),
	putdown(A),
	assert(move(unstack(A,X))),
	assert(move(putdown(A))).

/*holding goal
achieve(holding(A)) :-
	hold(A).

/*clear goal
achieve(clear(A)) :-
	clear_off(A).

/*handempty goal
achieve(handempty) :-
	holding(X),
        putdown(X),
	assert(move(putdown(X))).

